home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / dosrcss.zip / RCSUTIL.C < prev    next >
C/C++ Source or Header  |  1990-07-18  |  15KB  |  596 lines

  1. /*
  2.  *                     RCS utilities
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcsutil.c,v 5.4 90/07/16 21:40:37 lfk Release $ Purdue CS";
  6. #endif
  7.  
  8. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  9.    Distributed under license by the Free Software Foundation, Inc.
  10.  
  11. This file is part of RCS.
  12.  
  13. RCS is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation; either version 1, or (at your option)
  16. any later version.
  17.  
  18. RCS is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. GNU General Public License for more details.
  22.  
  23. You should have received a copy of the GNU General Public License
  24. along with RCS; see the file COPYING.  If not, write to
  25. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  
  27. Report problems and direct all questions to:
  28.  
  29.     rcs-bugs@cs.purdue.edu
  30.  
  31. */
  32.  
  33.  
  34.  
  35.  
  36. /* $Log:    rcsutil.c,v $
  37.  * Revision 5.4  90/07/16  21:40:37  lfk
  38.  * checkin for release compilation
  39.  * 
  40.  * Revision 5.3  90/07/15  18:06:08  lfk
  41.  * changed signals around so that
  42.  * they actually allow you to abort an RCS command
  43.  * 
  44.  * Revision 5.2  90/07/15  11:35:32  ROOT_DOS
  45.  * DOS version of RCS 4.0 checked in for MODS
  46.  * by lfk@athena.mit.edu
  47.  * Also update to MSC 6.0
  48.  * 
  49.  * revision 5.2 koya 90/01/25 00:37:14
  50.  * Modified the codes related to Child processes and Signals.
  51.  * 
  52.  * revision 5.1 koya 90/01/24 10:40:36
  53.  * Initial revision
  54.  * 
  55.  * Revision 4.6  89/05/01  15:13:40  narten
  56.  * changed copyright header to reflect current distribution rules
  57.  * 
  58.  * Revision 4.5  88/11/08  16:01:02  narten
  59.  * corrected use of varargs routines
  60.  * 
  61.  * Revision 4.4  88/11/08  12:00:28  narten
  62.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  63.  * 
  64.  * Revision 4.4  88/08/09  19:13:24  eggert
  65.  * Check for memory exhaustion.
  66.  * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
  67.  * Use execv(), not system(); yield exit status like diff(1)'s.
  68.  * 
  69.  * Revision 4.3  87/10/18  10:40:22  narten
  70.  * Updating version numbers. Changes relative to 1.1 actually
  71.  * relative to 4.1
  72.  * 
  73.  * Revision 1.3  87/09/24  14:01:01  narten
  74.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  75.  * warnings)
  76.  * 
  77.  * Revision 1.2  87/03/27  14:22:43  jenkins
  78.  * Port to suns
  79.  * 
  80.  * Revision 1.1  84/01/23  14:50:43  kcs
  81.  * Initial revision
  82.  * 
  83.  * Revision 4.1  83/05/10  15:53:13  wft
  84.  * Added getcaller() and findlock().
  85.  * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
  86.  * (needed for background jobs in older shells). Added restoreints().
  87.  * Removed printing of full RCS path from logcommand().
  88.  * 
  89.  * Revision 3.8  83/02/15  15:41:49  wft
  90.  * Added routine fastcopy() to copy remainder of a file in blocks.
  91.  *
  92.  * Revision 3.7  82/12/24  15:25:19  wft
  93.  * added catchints(), ignoreints() for catching and ingnoring interrupts;
  94.  * fixed catchsig().
  95.  *
  96.  * Revision 3.6  82/12/08  21:52:05  wft
  97.  * Using DATEFORM to format dates.
  98.  *
  99.  * Revision 3.5  82/12/04  18:20:49  wft
  100.  * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
  101.  * lockedby-field.
  102.  *
  103.  * Revision 3.4  82/12/03  17:17:43  wft
  104.  * Added check to addlock() ensuring only one lock per person.
  105.  * Addlock also returns a pointer to the lock created. Deleted fancydate().
  106.  *
  107.  * Revision 3.3  82/11/27  12:24:37  wft
  108.  * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
  109.  * Introduced macro SNOOP so that snoop can be placed in directory other than
  110.  * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
  111.  *
  112.  * Revision 3.2  82/10/18  21:15:11  wft
  113.  * added function getfullRCSname().
  114.  *
  115.  * Revision 3.1  82/10/13  16:17:37  wft
  116.  * Cleanup message is now suppressed in quiet mode.
  117.  */
  118.  
  119.  
  120.  
  121.  
  122. #include <sys/types.h>
  123. #include <sys/stat.h>
  124. #include <signal.h>
  125. #include "rcsbase.h"
  126. #ifndef MSDOS
  127. #include <pwd.h>
  128. #endif /* NOT MSDOS */
  129. #include <varargs.h>
  130.  
  131. #if defined(USG) || defined(V4_2BSD)
  132. #include <fcntl.h>
  133. #endif
  134.  
  135. #ifndef MSDOS
  136. #ifndef V4_2BSD
  137. #define vfork fork
  138. #endif
  139. #endif /* NOT MSDOS */
  140.  
  141. extern char * bindex();
  142. extern FILE * finptr;
  143. extern char * RCSfilename;
  144. #ifndef MSDOS
  145. extern char * getlogin();
  146. extern struct passwd *getpwuid();
  147. #endif /* NOT MSDOS */
  148. extern char * malloc();
  149.  
  150.  
  151. char * talloc(size)
  152. unsigned size;
  153. {
  154.     char * p;
  155.     if (!(p = malloc(size))) {
  156.         faterror("out of memory");
  157.     }
  158.     return p;
  159. }
  160.  
  161. #ifdef MSDOS
  162. char * getenv( char * var );
  163. #endif
  164.  
  165. char * getcaller()
  166. /* Function: gets the callers login from his uid.
  167.  * If the uid is root, tries to get the true login with getlogin().
  168.  */
  169. {
  170.     char *name = "ROOT_DOS";
  171.     char *tmpname;
  172. #ifdef MSDOS
  173. #    ifndef MKS
  174.     if ((tmpname = getenv("USR")) != NULL);
  175. #    else
  176.     if ((tmpname = getenv("LOGNAME")) != NULL);
  177. #    endif
  178.         name = tmpname;
  179.     return name;
  180. #else
  181.     int uid;
  182.     uid=getuid();
  183.     if (uid==0) {
  184.         /* super user; try getlogin() to distinguish */
  185.         name = getlogin();
  186.         if (name!=nil && *name!='\0')
  187.             return name;
  188.     }
  189.     return(getpwuid(uid)->pw_name);
  190. #endif /* MSDOS */
  191. }
  192.  
  193.  
  194.  
  195. struct hshentry * findlock(who,delete)
  196. char * who; int delete;
  197. /* Finds the first lock held by who and returns a pointer
  198.  * to the locked delta; also removes the lock if delete==true.
  199.  * Returns nil if there is no lock held by who.
  200.  */
  201. {
  202.         register struct lock * next, * trail;
  203.         struct lock dummy;
  204.  
  205.         dummy.nextlock=next=Locks;
  206.         trail = &dummy;
  207.         while (next!=nil) {
  208.                 if(strcmp(who,next->login)==0) break; /*found a lock*/
  209.                 trail=next;
  210.                 next=next->nextlock;
  211.         }
  212.         if (next!=nil) {
  213.         /* found one */
  214.         if (delete) {
  215.             /* delete it */
  216.             trail->nextlock=next->nextlock;
  217.             Locks=dummy.nextlock;
  218.             next->delta->lockedby=nil; /* reset locked-by */
  219.         }
  220.                 return next->delta;
  221.         } else  return nil;
  222. }
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230. struct lock * addlock(delta,who)
  231. struct hshentry * delta; char * who;
  232. /* Given a delta, addlock checks whether
  233.  * the delta is locked by somebody other than who.
  234.  * If so, an error message is printed, and false returned.
  235.  * If the delta is not reserved at all, a lock for it is added,
  236.  * and a pointer for the lock returned.
  237.  */
  238. {
  239.         struct lock * next;
  240.  
  241.         next=Locks;
  242.         while (next!=nil) {
  243.                 if (cmpnum(delta->num,next->delta->num)==0) {
  244.                         if (strcmp(who,next->login)==0)
  245.                                 return next;
  246.                                 /* lock exists already */
  247.                         else {
  248.                                 error("revision %s already locked by %s",
  249.                                       delta->num, next->login);
  250.                                 return false;
  251.                         }
  252.                 } else {
  253.                         if (strcmp(who,next->login)==0) {
  254.                                 error("you already locked %s; only one lock allowed per person.",
  255.                                        next->delta->num);
  256.                                 return false;
  257.                         } else {
  258.                                 next=next->nextlock;
  259.                         }
  260.                 }
  261.         }
  262.         /* not found; set up new lockblock */
  263.         next= (struct lock *) talloc(sizeof (struct lock));
  264.         delta->lockedby=next->login=who;
  265.         next->delta= delta;
  266.         next->nextlock=Locks;
  267.         Locks=next;
  268.         return next;
  269. }
  270.  
  271.  
  272.  
  273. int addsymbol(delta,name,rebind)
  274. struct hshentry * delta; char * name; int rebind;
  275. /* Function: adds a new symbolic name and associates it with node delta.
  276.  * If name already exists and rebind is true, the name is associated
  277.  * with the new delta; otherwise, an error message is printed and
  278.  * false returned. Returns true it successful.
  279.  */
  280. {       register struct assoc * next;
  281.         next=Symbols;
  282.         while (next!=nil) {
  283.                 if (strcmp(name,next->symbol)==0) {
  284.                         if (rebind) {
  285.                                 next->delta=delta;
  286.                                 return true;
  287.                         } else {
  288.                                 error("symbolic name %s already bound to %s",
  289.                                         name,next->delta->num);
  290.                                 return false;
  291.                         }
  292.                 } else  next = next->nextassoc;
  293.         }
  294.         /* not found; insert new pair. */
  295.         next = (struct assoc *) talloc(sizeof(struct assoc));
  296.         next->symbol=name;
  297.         next->delta=delta;
  298.         next->nextassoc=Symbols;
  299.         Symbols = next;
  300.         return true;
  301. }
  302.  
  303.  
  304.  
  305.  
  306. int checkaccesslist(who)
  307. char * who;
  308. /* function: Returns true if who is the superuser, the owner of the
  309.  * file, the access list is empty, or who is on the access list.
  310.  * Prints an error message and returns false otherwise.
  311.  */
  312. {
  313.         register struct access * next;
  314.         struct stat statbuf;
  315.  
  316. #ifdef MSDOS
  317.         if ((AccessList==nil) || (strcmp(who,"ROOT_DOS")==0))
  318. #else
  319.         if ((AccessList==nil) || (strcmp(who,"root")==0))
  320. #endif /* MSDOS */
  321.                 return true;
  322.  
  323.         next=AccessList;
  324.         do {
  325.                 if (strcmp(who,next->login)==0)
  326.                         return true;
  327.                 next=next->nextaccess;
  328.         } while (next!=nil);
  329.  
  330. #ifdef MSDOS
  331. #else
  332.         VOID fstat(fileno(finptr),&statbuf);  /* get owner of file */
  333.         if (getuid() == statbuf.st_uid) return true;
  334. #endif /* MSDOS */
  335.  
  336.         error("User %s not on the access list",who);
  337.         return false;
  338. }
  339.  
  340. /* In MSDOS, we have a few signals.     */
  341. /* So, we set signal handlar for only SIGINT. $Author: lfk $    */
  342.  
  343. #ifdef MSDOS
  344. void catchsig(void)
  345. #else
  346. static SIGNAL_TYPE catchsig(s)
  347. #endif /* MSDOS */
  348. {
  349.     ignoreints();
  350.         diagnose("\nRCS: cleaning up\n");
  351.         VOID cleanup();
  352.     exit(2);
  353. #ifdef lint
  354.     catchsig(s);
  355. #endif
  356. }
  357.  
  358. #ifndef MSDOS
  359. static sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM};
  360. #define SIGS (sizeof(sig)/sizeof(*sig))
  361. static SIGNAL_TYPE (*catcher[SIGS])();
  362. #endif /* NOT MSDOS */
  363.   void catchints()
  364.   {
  365. #ifdef MSDOS
  366.     signal(SIGINT, catchsig); /* $Author: lfk $ fixed this so Ctrl-C halts processing */
  367.     restoreints();
  368. #else
  369.     register i;
  370.     for (i=SIGS; 0<=--i; )
  371.         catcher[i]  =
  372.         signal(sig[i],SIG_IGN) == SIG_IGN  ?  SIG_IGN  :  catchsig;
  373.     restoreints();
  374. #endif /* MSDOS */
  375.   }
  376.  
  377.   void ignoreints()
  378.   {
  379. #ifdef MSDOS
  380.     VOID signal(SIGINT, SIG_IGN);
  381. #else
  382.     register i;
  383.     for (i=SIGS; 0<=--i; )
  384.         VOID signal(sig[i], SIG_IGN);
  385. #endif /* MSDOS */
  386.   }
  387.  
  388. void restoreints()
  389. {
  390. #ifdef MSDOS
  391.     VOID signal(SIGINT, catchsig);
  392. #else
  393.     register i;
  394.     for (i=SIGS; 0<=--i; )
  395.         if (catcher[i] != SIG_IGN)
  396.             VOID signal(sig[i], catcher[i]);
  397. #endif /* MSDOS */
  398. }
  399.  
  400. fastcopy(inf,outf)
  401. FILE * inf, * outf;
  402. /* Function: copies the remainder of file inf to outf. First copies the
  403.  * rest that is in the IO-buffer of inf character by character, and then
  404.  * copies the remainder in blocks.
  405.  */
  406. {       char buf[BUFSIZ];
  407.         register int rcount, wcount;
  408.  
  409.         /* write the rest of the buffer to outf */
  410.         while ((--inf->_cnt)>=0) {
  411.                 VOID putc(*inf->_ptr++&0377,outf);
  412.         }
  413.         if (fflush(outf) == EOF) {
  414.         writeerror();
  415.     }
  416.  
  417.         /*now read the rest of the file in blocks*/
  418.         while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) {
  419.                 wcount=write(fileno(outf),buf,rcount);
  420.                 if (wcount!=rcount) {
  421.                     writeerror();
  422.                 }
  423.         }
  424. }
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431. #ifdef SNOOPFILE
  432.  
  433. #include "time.h"
  434. extern struct tm* localtime();
  435. extern long time();
  436.  
  437. logcommand(commandname,delta, sequence,login)
  438. char* commandname; struct hshentry * delta, * sequence[];char * login;
  439. /* Function: start a process to write the file that
  440.  * logs the RCS command.
  441.  * Each line in the log file contains the following information:
  442.  * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
  443.  * total deltas present(t), creation date of delta(d), date of operation(o),
  444.  * login of caller, RCS file name.
  445.  */
  446. {
  447.         char logline[200];
  448.         char curdate[datelength];
  449.     char *inoutargs[5];
  450.         register int i, backward, forward;
  451.         long clock;
  452.         struct tm * tm;
  453.  
  454.         clock=time((long *)0);
  455.         tm=localtime(&clock);
  456.  
  457.         VOID sprintf(curdate,DATEFORM,
  458.                 tm->tm_year, tm->tm_mon+1, tm->tm_mday,
  459.                 tm->tm_hour, tm->tm_min, tm->tm_sec);
  460.  
  461.         i= backward=forward=0;
  462.         while(sequence[i]!=nil) {  /* count deltas to be applied*/
  463.         if (countnumflds(sequence[i]->num) == 2)
  464.                 backward++;  /* reverse delta */
  465.         else    forward++;   /* branch delta  */
  466.         i++;
  467.         }
  468.     VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s",
  469.         commandname,delta->num,backward,forward,TotalDeltas,delta->date,
  470.         curdate,login,bindex(getfullRCSname(),'/'));
  471.     inoutargs[0] = nil;
  472.     inoutargs[1] = nil;
  473.     inoutargs[2] = SNOOP;
  474.     inoutargs[3] = logline;
  475.     inoutargs[4] = nil;
  476.     VOID run_back(inoutargs);
  477. }
  478. #endif
  479.  
  480.  
  481. static int fdreopen(fd, file, flags, mode)
  482.     char *file;
  483. {
  484.     int newfd;
  485.     VOID close(fd);
  486.     newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode);
  487.     if (newfd < 0  ||  newfd == fd)
  488.         return newfd;
  489. #ifdef F_DUPFD
  490.     fd = fcntl(newfd, F_DUPFD, fd);
  491. #else
  492.     fd = dup2(newfd, fd);
  493. #endif
  494.     VOID close(newfd);
  495.     return fd;
  496. }
  497.  
  498. static void tryopen(fd,file,flags)
  499.     char *file;
  500. {
  501.     if (file  &&  fdreopen(fd,file,flags,0600) != fd) {
  502.         VOID write(fileno(stderr), file, strlen(file));
  503.         VOID write(fileno(stderr), ": cannot open\n", 14);
  504.         _exit(2);
  505.     }
  506. }
  507.  
  508.  
  509. /*
  510. /* Run in the background a command specified by the strings in 'inoutargs'.
  511. /* inoutargs[0], if nonnil, is the name of the input file.
  512. /* inoutargs[1], if nonnil, is the name of the output file.
  513. /* inoutargs[2..] form the command to be run in the background.
  514. /*/
  515. static int run_back(inoutargs)
  516.     register char **inoutargs;
  517. {
  518. #ifdef MSDOS
  519.     int result;
  520.     
  521.     if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
  522.         return -1;
  523.     tryopen(fileno(stdin), inoutargs[0], 0);
  524.     tryopen(fileno(stdout), inoutargs[1], -1);
  525.     result = spawnvp( 0, inoutargs[2], &inoutargs[2] );
  526.     return result;                
  527. #else
  528.     int pid;
  529.     if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
  530.         return -1;
  531.     if (!(pid = vfork())) {
  532.         tryopen(fileno(stdin), inoutargs[0], 0);
  533.         tryopen(fileno(stdout), inoutargs[1], -1);
  534.         VOID execv(inoutargs[2], &inoutargs[2]);
  535.         inoutargs[1] = "/bin/sh";
  536.         VOID execv(inoutargs[1], &inoutargs[1]);
  537.         VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
  538.         _exit(2);
  539.     }
  540.     return pid;
  541. #endif /* MSDOS */
  542. }
  543.  
  544. #define CARGSMAX 20
  545. /*
  546. /* Run a command.
  547. /* The first two arguments are the input and output files (if nonnil);
  548. /* the rest specify the command and its arguments.
  549. /*/
  550. int run(va_alist)
  551.     va_dcl
  552. {
  553.     va_list ap;
  554.     int pid, wstatus, w;
  555.     char *rgargs[CARGSMAX];
  556.     register i = 0;
  557.     va_start(ap);
  558.     rgargs[0] = va_arg(ap, char *);
  559.     rgargs[1] = va_arg(ap, char *);
  560.     for (i =2; i< CARGSMAX; i++) {
  561.         rgargs[i] = va_arg(ap, char *);
  562.         if (rgargs[i] == NULL)
  563.         break;
  564.     }
  565.     va_end(ap);
  566.     pid = run_back(rgargs);
  567. #ifndef MSDOS
  568.     if (pid < 0)
  569. #endif /* MSDOS */
  570.         return pid;
  571. #ifndef MSDOS
  572.     for (;;)
  573.         if ((w = wait(&wstatus)) < 0)
  574.             return w;
  575.         else if (w == pid)
  576.             return wstatus;
  577. #endif /* NOT MSDOS */
  578. }
  579.     
  580. #ifdef MSDOS
  581. int Rename( from, to )
  582. char    *from;
  583. char    *to;
  584. {
  585.     if ( access( to, 0 ) == 0 ) {
  586.         if ( chmod( to, S_IWRITE | S_IREAD ) == -1 )
  587.             return (-1);
  588.         if ( unlink(to) != 0 )
  589.             return (-1);
  590.     }        
  591.         return ( rename( from, to ) );
  592. }
  593. #endif /* MSDOS */
  594.     
  595.     
  596.